//! Parser module for the Cangjie language
//!
//! This module contains the recursive descent parser that converts
//! tokens into an Abstract Syntax Tree (AST).

use crate::lexer::{Token, TokenType, Lexer};
use crate::ast::*;

/// Cangjie Parser
///
/// A recursive descent parser that converts tokens into an AST.
pub struct Parser {
    tokens: Vec<Token>,
    current: usize,
}

impl Parser {
    /// Create a new parser with a vector of tokens
    pub fn new(tokens: Vec<Token>) -> Self {
        Self {
            tokens,
            current: 0,
        }
    }

    /// Parse a complete Cangjie file
    pub fn parse_file(&mut self) -> Result<File, ParseError> {
        let mut file = File {
            package: None,
            imports: Vec::new(),
            declarations: Vec::new(),
        };

        // Parse package declaration
        if self.match_token(TokenType::Package) {
            file.package = Some(self.parse_package_decl()?);
        }

        // Parse imports
        while self.match_token(TokenType::Import) {
            file.imports.push(self.parse_import_decl()?);
        }

        // Parse declarations
        while !self.is_at_end() {
            if let Some(decl) = self.parse_decl()? {
                file.declarations.push(decl);
            }
        }

        Ok(file)
    }

    /// Parse a package declaration
    fn parse_package_decl(&mut self) -> Result<PackageDecl, ParseError> {
        let mut package = PackageDecl {
            name: String::new(),
            path: Vec::new(),
        };

        // Parse package path (e.g., package a.b.c)
        while !self.check(TokenType::Newline) && !self.is_at_end() {
            if self.match_token(TokenType::Identifier) {
                let identifier = self.previous().value.clone();
                if !package.name.is_empty() {
                    package.path.push(package.name.clone());
                }
                package.name = identifier;
            } else if self.match_token(TokenType::Dot) {
                continue;
            } else {
                break;
            }
        }

        Ok(package)
    }

    /// Parse an import declaration
    fn parse_import_decl(&mut self) -> Result<ImportDecl, ParseError> {
        let mut import = ImportDecl {
            path: Vec::new(),
            alias: None,
        };

        // Parse import path
        while !self.check(TokenType::Newline) && !self.is_at_end() {
            if self.match_token(TokenType::Identifier) {
                import.path.push(self.previous().value.clone());
            } else if self.match_token(TokenType::Dot) {
                continue;
            } else if self.match_token(TokenType::Mul) {
                import.path.push("*".to_string());
                break;
            } else {
                break;
            }
        }

        // Check for alias
        if self.match_token(TokenType::As) {
            if self.match_token(TokenType::Identifier) {
                import.alias = Some(self.previous().value.clone());
            }
        }

        Ok(import)
    }

    /// Parse a declaration
    fn parse_decl(&mut self) -> Result<Option<Decl>, ParseError> {
        if self.check(TokenType::Class) {
            Ok(Some(Decl::Class(self.parse_class_decl()?)))
        } else if self.check(TokenType::Interface) {
            Ok(Some(Decl::Interface(self.parse_interface_decl()?)))
        } else if self.check(TokenType::Struct) {
            Ok(Some(Decl::Struct(self.parse_struct_decl()?)))
        } else if self.check(TokenType::Enum) {
            Ok(Some(Decl::Enum(self.parse_enum_decl()?)))
        } else if self.check(TokenType::Func) {
            Ok(Some(Decl::Function(self.parse_function_decl()?)))
        } else if self.check(TokenType::Let) || self.check(TokenType::Var) || self.check(TokenType::Const) {
            Ok(Some(Decl::Variable(self.parse_variable_decl()?)))
        } else {
            // Skip unknown tokens
            if !self.is_at_end() {
                self.advance();
            }
            Ok(None)
        }
    }

    /// Parse a class declaration
    fn parse_class_decl(&mut self) -> Result<ClassDecl, ParseError> {
        self.consume(TokenType::Class, "Expected 'class' keyword")?;

        let mut class = ClassDecl {
            name: String::new(),
            modifiers: Vec::new(),
            members: Vec::new(),
            superclass: None,
            interfaces: Vec::new(),
        };

        // Parse class name
        if self.match_token(TokenType::Identifier) {
            class.name = self.previous().value.clone();
        }

        // Parse class body
        self.consume(TokenType::LCurl, "Expected '{' after class name")?;

        while !self.check(TokenType::RCurl) && !self.is_at_end() {
            if let Some(decl) = self.parse_decl()? {
                class.members.push(decl);
            }
        }

        self.consume(TokenType::RCurl, "Expected '}' after class body")?;

        Ok(class)
    }

    /// Parse an interface declaration
    fn parse_interface_decl(&mut self) -> Result<InterfaceDecl, ParseError> {
        self.consume(TokenType::Interface, "Expected 'interface' keyword")?;

        let mut interface = InterfaceDecl {
            name: String::new(),
            modifiers: Vec::new(),
            members: Vec::new(),
            superinterfaces: Vec::new(),
        };

        // Parse interface name
        if self.match_token(TokenType::Identifier) {
            interface.name = self.previous().value.clone();
        }

        // Parse interface body
        self.consume(TokenType::LCurl, "Expected '{' after interface name")?;

        while !self.check(TokenType::RCurl) && !self.is_at_end() {
            if let Some(decl) = self.parse_decl()? {
                interface.members.push(decl);
            }
        }

        self.consume(TokenType::RCurl, "Expected '}' after interface body")?;

        Ok(interface)
    }

    /// Parse a struct declaration
    fn parse_struct_decl(&mut self) -> Result<StructDecl, ParseError> {
        self.consume(TokenType::Struct, "Expected 'struct' keyword")?;

        let mut struct_decl = StructDecl {
            name: String::new(),
            modifiers: Vec::new(),
            members: Vec::new(),
        };

        // Parse struct name
        if self.match_token(TokenType::Identifier) {
            struct_decl.name = self.previous().value.clone();
        }

        // Parse struct body
        self.consume(TokenType::LCurl, "Expected '{' after struct name")?;

        while !self.check(TokenType::RCurl) && !self.is_at_end() {
            if self.check(TokenType::Let) || self.check(TokenType::Var) || self.check(TokenType::Const) {
                struct_decl.members.push(self.parse_variable_decl()?);
            }
        }

        self.consume(TokenType::RCurl, "Expected '}' after struct body")?;

        Ok(struct_decl)
    }

    /// Parse an enum declaration
    fn parse_enum_decl(&mut self) -> Result<EnumDecl, ParseError> {
        self.consume(TokenType::Enum, "Expected 'enum' keyword")?;

        let mut enum_decl = EnumDecl {
            name: String::new(),
            modifiers: Vec::new(),
            members: Vec::new(),
        };

        // Parse enum name
        if self.match_token(TokenType::Identifier) {
            enum_decl.name = self.previous().value.clone();
        }

        // Parse enum body
        self.consume(TokenType::LCurl, "Expected '{' after enum name")?;

        while !self.check(TokenType::RCurl) && !self.is_at_end() {
            if self.match_token(TokenType::Identifier) {
                let member_name = self.previous().value.clone();
                enum_decl.members.push(EnumMember {
                    name: member_name,
                    value: None,
                });

                if !self.match_token(TokenType::Comma) {
                    break;
                }
            } else {
                break;
            }
        }

        self.consume(TokenType::RCurl, "Expected '}' after enum body")?;

        Ok(enum_decl)
    }

    /// Parse a function declaration
    fn parse_function_decl(&mut self) -> Result<FunctionDecl, ParseError> {
        self.consume(TokenType::Func, "Expected 'func' keyword")?;

        let mut func = FunctionDecl {
            name: String::new(),
            modifiers: Vec::new(),
            parameters: Vec::new(),
            return_type: None,
            body: None,
        };

        // Parse function name
        if self.match_token(TokenType::Identifier) {
            func.name = self.previous().value.clone();
        }

        // Parse parameters
        if self.match_token(TokenType::LParen) {
            if !self.check(TokenType::RParen) {
                func.parameters = self.parse_parameters()?;
            }
            self.consume(TokenType::RParen, "Expected ')' after parameters")?;
        }

        // Parse return type
        if self.match_token(TokenType::Colon) {
            if self.match_token(TokenType::Identifier) {
                func.return_type = Some(Type::Named(NamedType {
                    name: self.previous().value.clone(),
                }));
            }
        }

        // Parse function body
        if self.match_token(TokenType::LCurl) {
            let mut block = BlockStmt {
                statements: Vec::new(),
            };

            while !self.check(TokenType::RCurl) && !self.is_at_end() {
                // Skip for now, just advance
                self.advance();
            }

            self.consume(TokenType::RCurl, "Expected '}' after function body")?;
            func.body = Some(block);
        }

        Ok(func)
    }

    /// Parse function parameters
    fn parse_parameters(&mut self) -> Result<Vec<Parameter>, ParseError> {
        let mut parameters = Vec::new();

        while !self.check(TokenType::RParen) && !self.is_at_end() {
            if self.match_token(TokenType::Identifier) {
                let param_name = self.previous().value.clone();
                let mut param_type = None;

                if self.match_token(TokenType::Colon) {
                    if self.match_token(TokenType::Identifier) {
                        param_type = Some(Type::Named(NamedType {
                            name: self.previous().value.clone(),
                        }));
                    }
                }

                parameters.push(Parameter {
                    name: param_name,
                    type_annotation: param_type,
                    default_value: None,
                });

                if !self.match_token(TokenType::Comma) {
                    break;
                }
            } else {
                break;
            }
        }

        Ok(parameters)
    }

    /// Parse a variable declaration
    fn parse_variable_decl(&mut self) -> Result<VariableDecl, ParseError> {
        let is_mutable = self.match_token(TokenType::Var) || self.match_token(TokenType::Let);
        let is_const = self.match_token(TokenType::Const);

        let mut var = VariableDecl {
            name: String::new(),
            modifiers: Vec::new(),
            type_annotation: None,
            initializer: None,
            is_mutable: is_mutable || is_const,
        };

        // Parse variable name
        if self.match_token(TokenType::Identifier) {
            var.name = self.previous().value.clone();
        }

        // Parse type annotation
        if self.match_token(TokenType::Colon) {
            if self.match_token(TokenType::Identifier) {
                var.type_annotation = Some(Type::Named(NamedType {
                    name: self.previous().value.clone(),
                }));
            }
        }

        // Parse initializer
        if self.match_token(TokenType::Assign) {
            // For now, just skip the expression
            while !self.check(TokenType::Newline) && !self.check(TokenType::Semi) && !self.is_at_end() {
                self.advance();
            }
            var.initializer = Some(Expr::Identifier(Identifier {
                name: "placeholder".to_string(),
            }));
        }

        Ok(var)
    }

    // === Helper Methods ===

    /// Check if we've reached the end of tokens
    fn is_at_end(&self) -> bool {
        self.peek().token_type == TokenType::EndOfFile
    }

    /// Look at the current token
    fn peek(&self) -> &Token {
        if self.current >= self.tokens.len() {
            return &self.tokens[self.tokens.len() - 1];
        }
        &self.tokens[self.current]
    }

    /// Look at the previous token
    fn previous(&self) -> &Token {
        &self.tokens[self.current - 1]
    }

    /// Advance to the next token
    fn advance(&mut self) -> &Token {
        if !self.is_at_end() {
            self.current += 1;
        }
        self.previous()
    }

    /// Check if the current token matches any of the given types
    fn check(&self, token_type: TokenType) -> bool {
        if self.is_at_end() {
            return false;
        }
        self.peek().token_type == token_type
    }

    /// Try to match and consume a token of the given type
    fn match_token(&mut self, token_type: TokenType) -> bool {
        if self.check(token_type) {
            self.advance();
            true
        } else {
            false
        }
    }

    /// Consume a token of the given type or return an error
    fn consume(&mut self, token_type: TokenType, _message: &str) -> Result<&Token, ParseError> {
        if self.check(token_type) {
            Ok(self.advance())
        } else {
            Err(ParseError::UnexpectedToken {
                expected: format!("{:?}", token_type),
                found: format!("{:?}", self.peek().token_type),
                line: self.peek().line,
                column: self.peek().column,
            })
        }
    }
}

/// Parser error types
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
    #[error("Unexpected token: expected {expected}, found {found} at line {line}, column {column}")]
    UnexpectedToken {
        expected: String,
        found: String,
        line: usize,
        column: usize,
    },
    #[error("Invalid syntax: {message} at line {line}, column {column}")]
    InvalidSyntax {
        message: String,
        line: usize,
        column: usize,
    },
}